﻿using DotNetCore.CAP;
using DotNetCore.CAP.Messages;
using MediatR;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Reflection;
using static System.Collections.Specialized.BitVector32;

namespace Leo.Common.CAP
{
    public class DealQueue
    {
        public static void ExceDealQueue(FailedInfo failedInfo)
        {
            var mediator = failedInfo.ServiceProvider.GetRequiredService<IMediator>();

            if (failedInfo.MessageType == MessageType.Publish)
            {
                mediator.Publish(new DealQueueNoticeMessage(failedInfo));
            }

            if (failedInfo.MessageType == MessageType.Subscribe)
            {
            }
        }
    }

    public interface IDealQueueHandler
    {
        /// <summary>
        /// 是否执行
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        string GetRoutingKey();

        /// <summary>
        /// 处理程序
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        Task ExecuteHandlerAsync(FailedInfo info);
    }

    public class BusinnesDealHandler : IDealQueueHandler
    {
        private readonly IMediator mediator;

        public BusinnesDealHandler(IMediator mediator)
        {
            this.mediator = mediator;
        }

        public Task ExecuteHandlerAsync(FailedInfo info)
        {
            // 业务 补偿 代码
            Console.WriteLine("test");
            return Task.CompletedTask;
        }

        public string GetRoutingKey()
        {
            return "test.message";
        }
    }



    public class PublishDealQueueHandlerTest : INotificationHandler<DealQueueNoticeMessage>
    {
        private List<Type> types;

        private ConcurrentDictionary<string, IDealQueueHandler> cache = new ConcurrentDictionary<string, IDealQueueHandler>();

        public async Task Handle(DealQueueNoticeMessage notification, CancellationToken cancellationToken)
        {
            var routingkey = notification.Info.Message.GetName();
            if (types == null || !types.Any())
            {
                InitType();
            }

            // 存在
            if (cache.ContainsKey(routingkey))
            {
                cache.TryGetValue(routingkey, out IDealQueueHandler handler);

                if (handler != null)
                {
                    await handler.ExecuteHandlerAsync(notification.Info);
                    return;
                }
            }

            foreach (var type in types)
            {
                var provider = notification.Info.ServiceProvider.GetRequiredService(type) as IDealQueueHandler;
                if (provider.GetRoutingKey() == routingkey)
                {
                    await provider.ExecuteHandlerAsync(notification.Info);
                    if (!cache.ContainsKey(provider.GetRoutingKey()))
                    {
                        cache.TryAdd(provider.GetRoutingKey(), provider);
                    }
                }
            }

            return;
        }

        public void InitType()
        {
            types = new List<Type>();
            types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(assembiy => assembiy.GetTypes())
              .Where(r => r.IsClass && r.IsPublic && typeof(IDealQueueHandler).IsAssignableFrom(r)).ToList();
        }
    }



    /// <summary>
    /// 发布者 死信队列 处理程序
    /// </summary>
    public class PublishDealQueueHandler : ICapSubscribe
    {
        private ConcurrentDictionary<string, IDealQueueHandler> cache = new ConcurrentDictionary<string, IDealQueueHandler>();

        private List<Type> types = new List<Type>();

        public PublishDealQueueHandler()
        {
            types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(assembiy => assembiy.GetTypes())
              .Where(r => r.IsClass && r.IsPublic && typeof(IDealQueueHandler).IsAssignableFrom(r)).ToList();
            Console.WriteLine(types.Count());
            Init();
        }
        [CapSubscribe("publish.deal.queue", Group = "PublishDealQueue")]
        public void Handler(FailedInfo info)
        {
            if (cache.TryGetValue(info.Message.GetName(), out var handler))
            {
                handler.ExecuteHandlerAsync(info);
            }
        }

        private void Init()
        {
            foreach (var type in types)
            {
                var handler = Activator.CreateInstance(type) as IDealQueueHandler;

                if (!cache.ContainsKey(handler.GetRoutingKey()))
                {
                    cache.TryAdd(handler.GetRoutingKey(), handler);
                }
            }
        }
    }
}
